/**
 * SortedRing.java
 * ************************** 
 * @date May 5, 2011
 * @author Michele Tamburini
 * 
 * **************************
 */
package gossipServices.bootstraping.tman.rankingMethods;

import gossipServices.basic.nodeDescriptors.NodeDescriptor;
import gossipServices.basic.view.ConcretePartialView;
import gossipServices.basic.view.PartialView;
import gossipServices.bootstraping.tman.rankingMethods.rankingComparators.NodeIDSorter;
import gossipServices.bootstraping.tman.rankingMethods.rankingComparators.RankSorter;

import java.util.Collections;
import java.util.List;
import java.util.Vector;

/**
 * Description: 
 * This class is a TManRankingMethod and extends the GeneralRankingMethod.
 * It produces in output a sorted ring among the input nodes
 * according to the distance of their NodeID(s).
 * The steps followed in order to produce the ring are:
 *  1) create a sorted ring from the set of input nodes also including
 *  	the base node,
 *  2) assign a rank value to each node defined as the minimal hop
		count to the node from the baseNode in this ring,
	3) OUTPUT: list of the input NodeDescriptor(s) ordered according to the
		rank value. 
 *
 */
public class SortedRing extends GeneralRankingMethod {
	

	/**
	 * @param targetViewSize
	 */
	public SortedRing(int targetViewSize) {
		super(targetViewSize);
	}

	@Override
	public PartialView rank(NodeDescriptor baseNode, PartialView inputView) {
		pairsList = new Vector<RankingPair>();
		RankingPair baseNodePair = new RankingPair(baseNode, 0);
		//creating a list of pairs with the NodeDescriptor and a ranking value 
		for(int i=0; i < inputView.size(); i++){
			pairsList.add(new RankingPair(inputView.getAt(i), 0));
		}
		
		//remove any additional occurrence of the baseNode
		while( pairsList.contains(baseNodePair) )
			pairsList.remove(baseNodePair);
		
		/* adding also the base note in order to find its position
		 * among the set of inputed nodes 
		 */
		pairsList.add(baseNodePair);
		
		/*
		 * 1) creating a sorted ring from the set of input nodes.
		 * 	  The ring also contains the base node
		 */
		createRing();
		
		
		/*
		 * 2) assign a rank value to each node defined as the minimal hop
		 * 	  count to the node from the baseNode in this ring.
		 */
		assignRankValue(baseNodePair, pairsList);
		pairsList.remove(baseNodePair);
		
		/*
		 * 3) OUTPUT: list of the input NodeDescriptor(s) ordered according to the
		 *    rank value.
		 */
		synchronized (pairsList) {
			Collections.sort(pairsList, new RankSorter());
//			Collections.sort(pairsList, new DistasnceIDSorter(baseNode));
		}
		
		PartialView outPutView = (new ConcretePartialView(extracNodeFromPairs())).head(targetViewSize_K);
		return outPutView;
	}

	/**
	 * The sortedRing is built simply by the ordering of the 
	 * list of NodeDescriptor(s) in which is also inserted the
	 * baseNode. After that we can go on with the ranking.
	 */
	protected void createRing() {
		synchronized (pairsList) {
			Collections.sort(pairsList, new NodeIDSorter());			
		}
	}

	/**
	 * We have to assign a number (the ranking value) to 
	 * each position into the list. 
	 * Starting from the baseNode, which has the rank 0,
	 * we start to assign an increasing value in both 
	 * directions until we reach the starting point
	 * (acting as into a circular list). 
	 * These values go from 1 to n/2-1. 
	 * @param baseNodePair
	 * @param pairsList
	 */
	protected void assignRankValue(RankingPair baseNodePair,
			List<RankingPair> pairsList) {
		int indexBaseNode = pairsList.indexOf(baseNodePair);
		int size = pairsList.size();
		int minus;
		
		for(int hops=0; hops<=(size/2); hops++){
			minus =indexBaseNode - hops; 
			if(minus < 0)
				pairsList.get(size+minus).setRank(hops);
			else
				pairsList.get(minus).setRank(hops);
			pairsList.get((indexBaseNode + hops)%size).setRank(hops);
		}
	}


}
